# swift/test/lit.cfg - Configuration for the 'lit' test runner -*- python -*-
#
# This source file is part of the Swift.org open source project
#
# Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
# Licensed under Apache License v2.0 with Runtime Library Exception
#
# See https://swift.org/LICENSE.txt for license information
# See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
#
# -----------------------------------------------------------------------------
#
# This is a configuration file for the 'lit' test runner.
#
# Refer to docs/Testing.md for documentation.
#
# Update docs/Testing.md when changing this file.
#
# -----------------------------------------------------------------------------

from __future__ import absolute_import
import os
import platform
import re
import shlex
import shutil
import subprocess
import sys
import socket
import glob
import pipes
from distutils.sysconfig import get_python_lib

import lit
import lit.formats
import lit.util

import site
site.addsitedir(os.path.dirname(__file__))
import swift_test

def make_path(*args):
    return os.path.normpath(os.path.join(*args))

#
# Helper functions.
#

def darwin_get_sdk_version(sdk_path):
    system_version_plist_path = make_path(sdk_path, "System", "Library",
                                          "CoreServices", "SystemVersion.plist")
    name = subprocess.check_output(
        ["defaults", "read", system_version_plist_path,
         "ProductName"]).rstrip()
    vers = subprocess.check_output(
        ["defaults", "read", system_version_plist_path,
         "ProductVersion"]).rstrip()
    build = subprocess.check_output(
        ["defaults", "read", system_version_plist_path,
         "ProductBuildVersion"]).rstrip()
    return (name, vers, build)

# Run sw_vers on the target to be tested and return the results.
def darwin_get_sw_vers(commandPrefix=[]):
    name = lit.util.executeCommand(
        commandPrefix + ['/usr/bin/sw_vers', '-productName'])[0].rstrip()
    vers = lit.util.executeCommand(
        commandPrefix + ['/usr/bin/sw_vers', '-productVersion'])[0].rstrip()
    build = lit.util.executeCommand(
        commandPrefix + ['/usr/bin/sw_vers', '-buildVersion'])[0].rstrip()
    return (name, vers, build)

def darwin_get_ios_sim_vers():
    sim_output = subprocess.check_output(['xcrun', 'simctl', 'list', 'runtimes'])
    ios_version_str = re.findall(r'iOS \d+\.*\d*', sim_output.decode('utf-8'))
    return [float(v.strip('iOS')) for v in ios_version_str]

# Returns the "prefix" command that should be prepended to the command line to
# run an executable compiled for iOS or AppleTV simulator.
def get_simulator_command(run_os, run_cpu, sdk_path):
    (name, vers, build) = darwin_get_sdk_version(sdk_path)
    if run_os == 'ios':
        if run_cpu == "i386":
            if min(darwin_get_ios_sim_vers()) > 10.3:
                print("ERROR: Your system does not have a 32-bit iOS simulator installed.")
                print("INFO: 1. Install iOS 10.3 or older simulator (Xcode -> Preferences -> Components -> Simulators).")
                print("INFO: 2. Create a 32-bit iPhone 5 device. Run:")
                print("INFO:    $ xcrun simctl create 'iPhone 5' com.apple.CoreSimulator.SimDeviceType.iPhone-5 com.apple.CoreSimulator.SimRuntime.iOS-10-3")
                sys.exit(1)
            else:
                return "simctl spawn --standalone 'iPhone 5'"
        else:
            return "simctl spawn --standalone 'iPhone 8'"
    elif run_os == 'tvos':
        return "simctl spawn --standalone 'Apple TV 4K'"
    elif run_os == 'watchos':
        return "simctl spawn --standalone 'Apple Watch Series 4 - 44mm'"
    else:
        lit_config.fatal("Unknown simulator OS %r" % run_os)

def get_lldb_python_path(lldb_build_root):
    lldb_path = os.path.join(lldb_build_root, 'bin', 'lldb')
    if not os.access(lldb_path, os.F_OK):
        return None
    return subprocess.check_output([lldb_path, "-P"]).rstrip().decode('utf-8')

def get_lldb_python_interpreter(lldb_build_root):
    python_path = os.path.join(lldb_build_root, 'bin', 'lldb-python')
    if not os.access(python_path, os.F_OK):
        return None
    return python_path

###

# Check that the object root is known.
if config.test_exec_root is None:
    # Otherwise, we haven't loaded the site specific configuration (the user is
    # probably trying to run on a test file directly, and either the site
    # configuration hasn't been created by the build system, or we are in an
    # out-of-tree build situation).

    # Check for 'swift_site_config' user parameter, and use that if available.
    site_cfg = lit_config.params.get('swift_site_config', None)
    if site_cfg and os.path.exists(site_cfg):
        lit_config.load_config(config, site_cfg)
        raise SystemExit

    lit_config.fatal("lit must be pointed at a build folder")

###

# name: The name of this test suite.
config.name = 'Swift(%s)' % config.variant_suffix[1:]

# Respect the TOOLCHAINS environment variable when deciding the xcrun
# toolchain for Darwin platforms.
if platform.system() == 'Darwin':
    config.environment['TOOLCHAINS'] = \
        os.environ.get('TOOLCHAINS', config.darwin_xcrun_toolchain)

# NOTE: this mirrors the kIsWindows from lit.lit.TestRunner in LLVM
kIsWindows = platform.system() == 'Windows'

# testFormat: The test format to use to interpret tests.

# Choose between lit's internal shell pipeline runner and a real shell.  If
# LIT_USE_INTERNAL_SHELL is in the environment, we use that as an override.
use_lit_shell = os.environ.get('LIT_USE_INTERNAL_SHELL', kIsWindows)
if not use_lit_shell:
    config.available_features.add('shell')

config.test_format = swift_test.SwiftTest(coverage_mode=config.coverage_mode,
                                          execute_external=not use_lit_shell)

# suffixes: A list of file extensions to treat as test files.
config.suffixes = ['.swift', '.ll', '.sil', '.gyb', '.m', '.c',
                   '.swiftinterface', '.test-sh', '.test']

# excludes: A list of directories to exclude from the testsuite. The 'Inputs'
# subdirectories contain auxiliary inputs for various tests in their parent
# directories.
config.excludes = ['Inputs']

if lit_config.params.get('disable_unittests', None) is not None:
    config.excludes += ['Unit']

# test_source_root: The root path where tests are located.
config.test_source_root = os.path.dirname(__file__)

# test_exec_root: The root path where tests should be run.
swift_obj_root = getattr(config, 'swift_obj_root', None)

# cmake. The path to the cmake executable we used to configure swift.
assert(config.cmake)
config.substitutions.append( ('%cmake',  config.cmake) )
lit_config.note('Using cmake: ' + config.cmake)

# Set llvm_{src,obj}_root for use by others.
config.llvm_src_root = getattr(config, 'llvm_src_root', None)
config.llvm_obj_root = getattr(config, 'llvm_obj_root', None)

if platform.system() == 'OpenBSD':
    llvm_libs_dir = getattr(config, 'llvm_libs_dir', None)
    if not llvm_libs_dir:
        lit_config.fatal('No LLVM libs dir set.')
    config.environment['LD_LIBRARY_PATH'] = llvm_libs_dir

def append_to_env_path(directory):
    config.environment['PATH'] = \
        os.path.pathsep.join((directory, config.environment['PATH']))

if sys.version_info[0] >= 3:
    config.environment['PYTHONIOENCODING'] = 'UTF8'

# Tweak the PATH to include the tools dir and the scripts dir.
if swift_obj_root is not None:
    llvm_tools_dir = getattr(config, 'llvm_tools_dir', None)
    if not llvm_tools_dir:
        lit_config.fatal('No LLVM tools dir set!')
    append_to_env_path(llvm_tools_dir)

    build_mode = lit_config.params.get('build_mode', '')
    append_to_env_path(make_path(swift_obj_root, build_mode, 'bin'))

native_llvm_tools_path = lit_config.params.get('native_llvm_tools_path')
if native_llvm_tools_path is not None:
    append_to_env_path(native_llvm_tools_path)

native_clang_tools_path = lit_config.params.get('native_clang_tools_path')
if native_clang_tools_path is not None:
    append_to_env_path(native_clang_tools_path)

native_swift_tools_path = lit_config.params.get('native_swift_tools_path')
if native_swift_tools_path is not None:
    append_to_env_path(native_swift_tools_path)

###

# Discover the Swift binaries to use.
def inferSwiftBinary(binaryName):
    # Determine which executable to use.
    envVarName = binaryName.upper().replace("-", "_")
    execPath = os.getenv(envVarName)

    # If the user set the variable in the environment, definitely use that and
    # don't try to validate.
    if execPath:
        return execPath

    # Otherwise look in the path.
    PATH = config.environment['PATH']
    execPath = lit.util.which(binaryName, PATH)

    if execPath:
        if not lit_config.quiet:
            lit_config.note('using %s: %s' % (binaryName, execPath))
    else:
        msg = "couldn't find '%s' program, try setting %s in your environment"
        lit_config.warning(msg % (binaryName, envVarName))

        # Just substitute the plain executable name, so the run line remains
        # reasonable.
        execPath = binaryName

    return execPath

if 'gmalloc' in lit_config.params:
    config.environment['DYLD_INSERT_LIBRARIES'] = '/usr/lib/libgmalloc.dylib'
    config.environment['MALLOC_LOG_FILE'] = '/dev/null'
    config.available_features.add('gmalloc')

config.swift_frontend = inferSwiftBinary('swift-frontend')
config.swift = inferSwiftBinary('swift')
config.swiftc = inferSwiftBinary('swiftc')
config.sil_opt = inferSwiftBinary('sil-opt')
config.sil_func_extractor = inferSwiftBinary('sil-func-extractor')
config.sil_llvm_gen = inferSwiftBinary('sil-llvm-gen')
config.sil_nm = inferSwiftBinary('sil-nm')
config.sil_passpipeline_dumper = inferSwiftBinary('sil-passpipeline-dumper')
config.lldb_moduleimport_test = inferSwiftBinary('lldb-moduleimport-test')
config.swift_ide_test = inferSwiftBinary('swift-ide-test')
config.swift_dependency_tool = inferSwiftBinary('swift-dependency-tool')
config.swift_syntax_test = inferSwiftBinary('swift-syntax-test')
if 'syntax_parser_lib' in config.available_features:
    config.swift_syntax_parser_test = inferSwiftBinary('swift-syntax-parser-test')
config.swift_reflection_dump = inferSwiftBinary('swift-reflection-dump')
config.swift_remoteast_test = inferSwiftBinary('swift-remoteast-test')
config.swift_indent = inferSwiftBinary('swift-indent')
config.swift_symbolgraph_extract = inferSwiftBinary('swift-symbolgraph-extract')
config.clang = inferSwiftBinary('clang')
config.llvm_link = inferSwiftBinary('llvm-link')
config.swift_llvm_opt = inferSwiftBinary('swift-llvm-opt')
config.llvm_profdata = inferSwiftBinary('llvm-profdata')
config.llvm_cov = inferSwiftBinary('llvm-cov')
config.llvm_strings = inferSwiftBinary('llvm-strings')
config.filecheck = inferSwiftBinary('FileCheck')
config.llvm_dwarfdump = inferSwiftBinary('llvm-dwarfdump')
config.llvm_readelf = inferSwiftBinary('llvm-readelf')
config.llvm_dis = inferSwiftBinary('llvm-dis')
config.llvm_nm = inferSwiftBinary('llvm-nm')
config.sourcekitd_test = inferSwiftBinary('sourcekitd-test')
config.complete_test = inferSwiftBinary('complete-test')
config.swift_api_digester = inferSwiftBinary('swift-api-digester')
config.swift_refactor = inferSwiftBinary('swift-refactor')
config.swift_demangle_yamldump = inferSwiftBinary('swift-demangle-yamldump')
config.benchmark_o = inferSwiftBinary('Benchmark_O')
config.benchmark_driver = inferSwiftBinary('Benchmark_Driver')
config.wasmer = inferSwiftBinary('wasmer')
config.wasm_ld = inferSwiftBinary('wasm-ld')

config.swift_utils = make_path(config.swift_src_root, 'utils')
config.line_directive = make_path(config.swift_utils, 'line-directive')
config.gyb = make_path(config.swift_utils, 'gyb.py')
config.rth = make_path(config.swift_utils, 'rth') # Resilience test helper
config.scale_test = make_path(config.swift_utils, 'scale-test')
config.PathSanitizingFileCheck = make_path(config.swift_utils, 'PathSanitizingFileCheck')
config.swift_lib_dir = make_path(config.swift, '..', '..', 'lib')
config.round_trip_syntax_test = make_path(config.swift_utils, 'round-trip-syntax-test')

config.link = lit.util.which('link', config.environment.get('PATH', '')) or      \
              lit.util.which('lld-link', config.environment.get('PATH', ''))

# Find the resource directory.  Assume it's near the swift compiler if not set.
test_resource_dir = lit_config.params.get('test_resource_dir')
if test_resource_dir:
    resource_dir_opt = ("-resource-dir %s" % test_resource_dir)
else:
    test_resource_dir = make_path(config.swift_lib_dir, 'swift')
    resource_dir_opt = ""
stdlib_resource_dir_opt = resource_dir_opt
sourcekitd_framework_dir = config.swift_lib_dir
config.substitutions.append( ('%test-resource-dir', test_resource_dir) )
lit_config.note('Using resource dir: ' + test_resource_dir)

# Parse the variant triple.
(run_cpu, run_vendor, run_os, run_vers) = re.match('([^-]+)-([^-]+)-([^0-9]+)(.*)', config.variant_triple).groups()
if run_os == 'ios' and run_vers.endswith('-macabi'):
    run_vers = run_vers[0:-len('-macabi')]
    run_os = 'maccatalyst'
if run_vers.endswith('-simulator'):
    run_vers = run_vers[0:-len('-simulator')]
    run_environment='-simulator'
else:
    run_environment=''

target_arch = run_cpu
if run_os == 'openbsd' and run_cpu == 'amd64':
   target_arch = run_cpu
   run_cpu = 'x86_64'

run_ptrsize = '64' if ('64' in run_cpu or run_cpu == "s390x") else '32'
run_ptrauth = 'ptrauth' if run_cpu == 'arm64e' else 'noptrauth'
run_endian = 'little' if run_cpu != 's390x' else 'big'

sdk_overlay_link_path = ""
sdk_overlay_linker_opt = ""
sdk_overlay_dir_opt = ""
test_sdk_overlay_dir = lit_config.params.get('test_sdk_overlay_dir', None)
if test_sdk_overlay_dir is not None:
    config.available_features.add('sdk_overlay')

    sdk_overlay_dir_opt = ("-I %s" % make_path(test_sdk_overlay_dir, run_cpu))
    sdk_overlay_link_path_dir = make_path(test_sdk_overlay_dir, run_cpu)
    sdk_overlay_link_path = ("-L %s" % sdk_overlay_link_path_dir)
    sdk_overlay_linker_opt = (
        "-L %s -Xlinker -rpath -Xlinker %s" %
        (sdk_overlay_link_path_dir, sdk_overlay_link_path_dir))
    lit_config.note('Using SDK overlay dir: ' + test_sdk_overlay_dir)
    resource_dir_opt += (" %s" % sdk_overlay_dir_opt)

# Default to Swift 4 for now.
# Note that this accepts both `--param swift-version` (like the compiler flag)
# and `--param swift_version` (like a lit configuration parameter).
swift_version = lit_config.params.get('swift-version',
    lit_config.params.get('swift_version', '4'))
lit_config.note('Compiling with -swift-version ' + swift_version)
config.swift_test_options = '-swift-version ' + swift_version

differentiable_programming = lit_config.params.get('differentiable_programming', None)
if differentiable_programming is not None:
    config.available_features.add('differentiable_programming')

test_options = os.environ.get('SWIFT_TEST_OPTIONS')
if test_options:
    config.swift_test_options += ' '
    config.swift_test_options += test_options

config.swift_frontend_test_options = os.environ.get('SWIFT_FRONTEND_TEST_OPTIONS', '')
config.swift_frontend_test_options += ' -ignore-module-source-info'
config.swift_driver_test_options = os.environ.get('SWIFT_DRIVER_TEST_OPTIONS', '')
config.swift_driver_test_options += ' -Xfrontend'
config.swift_driver_test_options += ' -ignore-module-source-info'
config.sil_test_options = os.environ.get('SIL_TEST_OPTIONS', '')

config.clang_module_cache_path = make_path(config.swift_test_results_dir, "clang-module-cache")
shutil.rmtree(config.clang_module_cache_path, ignore_errors=True)
mcp_opt = "-module-cache-path %r" % config.clang_module_cache_path
clang_mcp_opt = "-fmodules-cache-path=%r" % config.clang_module_cache_path
lit_config.note("Using Clang module cache: " + config.clang_module_cache_path)
lit_config.note("Using test results dir: " + config.swift_test_results_dir)

completion_cache_path = make_path(config.swift_test_results_dir, "completion-cache")
shutil.rmtree(completion_cache_path, ignore_errors=True)
ccp_opt = "-completion-cache-path %r" % completion_cache_path
lit_config.note("Using code completion cache: " + completion_cache_path)

config.substitutions.append( ('%validate-incrparse', '%{python} %utils/incrparse/validate_parse.py --temp-dir %t --swift-syntax-test %swift-syntax-test') )
config.substitutions.append( ('%incr-transfer-tree', '%{python} %utils/incrparse/incr_transfer_tree.py --temp-dir %t --swift-syntax-test %swift-syntax-test') )
config.substitutions.append( ('%llvm_obj_root', config.llvm_obj_root) )
config.substitutions.append( ('%llvm_src_root', config.llvm_src_root) )
config.substitutions.append( ('%swift_obj_root', config.swift_obj_root) )
config.substitutions.append( ('%swift_src_root', config.swift_src_root) )
config.substitutions.append( ('%{python}', pipes.quote(sys.executable)) )
config.substitutions.append( ('%{python.unquoted}', sys.executable) )
config.substitutions.append( ('%mcp_opt', mcp_opt) )
config.substitutions.append( ('%swift_driver_plain', "%r" % config.swift) )
config.substitutions.append( ('%swiftc_driver_plain', "%r" % config.swiftc) )
config.substitutions.append( ('%swift_frontend_plain', "%r" % config.swift_frontend))

if kIsWindows:
    config.substitutions.append( ('%swift_driver',
                                  "%r %s %s %s -libc %s" % (config.swift, mcp_opt,
                                                            config.swift_test_options,
                                                            config.swift_driver_test_options,
                                                            config.swift_stdlib_msvc_runtime)) )
    config.substitutions.append( ('%swiftc_driver',
                                  "%r -toolchain-stdlib-rpath %s %s %s" % (config.swiftc, mcp_opt,
                                                                           config.swift_test_options,
                                                                           config.swift_driver_test_options)) )
else:
    config.substitutions.append( ('%swift_driver', "env SDKROOT=%s %r %s %s %s" % (config.variant_sdk, config.swift, mcp_opt, config.swift_test_options, config.swift_driver_test_options)) )
    config.substitutions.append( ('%swiftc_driver', "env SDKROOT=%s %r -toolchain-stdlib-rpath -Xlinker -rpath -Xlinker /usr/lib/swift %s %s %s" % (config.variant_sdk, config.swiftc, mcp_opt, config.swift_test_options, config.swift_driver_test_options)) )
config.substitutions.append( ('%sil-opt', "%r %s %s" % (config.sil_opt, mcp_opt, config.sil_test_options)) )
config.substitutions.append( ('%sil-func-extractor', "%r %s" % (config.sil_func_extractor, mcp_opt)) )
config.substitutions.append( ('%sil-llvm-gen', "%r %s" % (config.sil_llvm_gen, mcp_opt)) )
config.substitutions.append( ('%sil-nm', "%r %s" % (config.sil_nm, mcp_opt)) )
config.substitutions.append( ('%sil-passpipeline-dumper', "%r" % (config.sil_passpipeline_dumper)) )
config.substitutions.append( ('%lldb-moduleimport-test', "%r %s" % (config.lldb_moduleimport_test, mcp_opt)) )
config.substitutions.append( ('%lldb-moduleimport-test-with-sdk',
                             '%s -sdk %r' % (config.lldb_moduleimport_test, config.variant_sdk)) )
config.substitutions.append( ('%swift-dump-pcm', "%r -dump-pcm" % config.swiftc) )
config.substitutions.append( ('%swift-ide-test_plain', config.swift_ide_test) )
config.substitutions.append( ('%swift-ide-test', "%r %s %s -swift-version %s" % (config.swift_ide_test, mcp_opt, ccp_opt, swift_version)) )
config.substitutions.append( ('%swift-dependency-tool', config.swift_dependency_tool) )
config.substitutions.append( ('%swift-syntax-test', config.swift_syntax_test) )
if 'syntax_parser_lib' in config.available_features:
    config.substitutions.append( ('%swift-syntax-parser-test', config.swift_syntax_parser_test) )
# For testing on CI
if '-enable-astscope-lookup' in config.swift_test_options:
    config.available_features.add("enable-astscope-lookup")
if '-disable-astscope-lookup' in config.swift_test_options:
    config.available_features.add("disable-astscope-lookup")
if '-disable-parser-lookup' in config.swift_test_options:
    config.available_features.add("disable-parser-lookup")
config.substitutions.append( ('%swift-indent', config.swift_indent) )
config.substitutions.append( ('%llvm-link', config.llvm_link) )
config.substitutions.append( ('%swift-llvm-opt', config.swift_llvm_opt) )
config.substitutions.append( ('%llvm-dwarfdump', config.llvm_dwarfdump) )
config.substitutions.append( ('%llvm-readelf', config.llvm_readelf) )
config.substitutions.append( ('%llvm-dis', config.llvm_dis) )
config.substitutions.append( ('%llvm-nm', config.llvm_nm) )
config.substitutions.append( ('%swift-demangle-yamldump', config.swift_demangle_yamldump) )
config.substitutions.append( ('%Benchmark_O', config.benchmark_o) )
config.substitutions.append( ('%Benchmark_Driver', config.benchmark_driver) )
config.substitutions.append( ('%llvm-strings', config.llvm_strings) )
config.substitutions.append( ('%target-ptrauth', run_ptrauth ) )
config.substitutions.append( ('%swift-path', config.swift) )

# This must come after all substitutions containing "%swift".
config.substitutions.append(
    ('%swift',
     "%r %s -disable-objc-attr-requires-foundation-module %s %s"
       % (config.swift_frontend, mcp_opt, config.swift_test_options, config.swift_frontend_test_options)) )

config.clang_include_dir = make_path(config.swift, '..', '..', 'include')
config.substitutions.append( ('%clang-include-dir', config.clang_include_dir) )

# Use this to build the basic set of Objective-C overlays.
config.substitutions.append(('%build-clang-importer-objc-overlays',
                             '%target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -enable-objc-interop -emit-module -o %t %clang-importer-sdk-path/swift-modules/ObjectiveC.swift -disable-objc-attr-requires-foundation-module && '
                             '%target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -enable-objc-interop -emit-module -o %t %clang-importer-sdk-path/swift-modules/CoreGraphics.swift && '
                             '%target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -enable-objc-interop -emit-module -o %t %clang-importer-sdk-path/swift-modules/CoreFoundation.swift && '
                             '%target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -enable-objc-interop -emit-module -o %t %clang-importer-sdk-path/swift-modules/Foundation.swift'))

# FIXME: BEGIN -enable-source-import hackaround
config.substitutions.append(('%clang-importer-sdk-path',
                             '%r' % (make_path(config.test_source_root, 'Inputs', 'clang-importer-sdk'))))

config.substitutions.append(('%clang-importer-sdk-nosource',
                             '-sdk %r' % (make_path(config.test_source_root, 'Inputs', 'clang-importer-sdk'))))
# FIXME: END -enable-source-import hackaround

config.substitutions.append(('%clang-importer-sdk',
                             '-enable-source-import -sdk %r -I %r ' % (make_path(config.test_source_root, 'Inputs', 'clang-importer-sdk'),
                                                                       make_path(config.test_source_root, 'Inputs', 'clang-importer-sdk', 'swift-modules'))))

config.substitutions.append( ('%clang_apinotes',
                              "%r -cc1apinotes" %
                                (config.clang)) )

# This must come after all substitutions containing "%clang".
# Note: %clang is the locally-built clang.
# To get Xcode's clang, use %target-clang.
config.substitutions.append( ('%clang',
                              "%r %s" %
                                (config.clang, clang_mcp_opt)) )

###

def disallow(execName):
  warning = '''
    echo '*** Do not use \'{0}\' in tests; use \'%''{0}\'. ***' &&
    exit 1 && echo
  '''
  config.substitutions.append((' {0} '.format(execName),
                               warning.format(execName)))

disallow('swift')
disallow('swiftc')
disallow('swift_driver')
disallow('swiftc_driver')
disallow('sil-opt')
disallow('sil-func-extractor')
disallow('sil-llvm-gen')
disallow('sil-nm')
disallow('sil-passpipeline-dumper')
disallow('lldb-moduleimport-test')
disallow('swift-ide-test')
disallow('clang')
disallow('FileCheck')
disallow('llvm-dwarfdump')
disallow('llvm-dis')

config.substitutions.insert(0,
    ('%p',
     '$(echo "*** Use %""S instead of %""p in the Swift test suite ***" >&2)'))

###

# Set available features we allow tests to conditionalize on.
if platform.system() != 'Windows':
    config.available_features.add('crash-recovery')

# Add each available build target CPU as a feature.
for target in config.llvm_code_generators:
  config.available_features.add("CODEGENERATOR=" + target)

# Add the run target CPU, OS, and pointer size as features.
config.available_features.add("CPU=" + run_cpu)
config.available_features.add("OS=" + run_os)
config.available_features.add("PTRSIZE=" + run_ptrsize)
config.available_features.add("VENDOR=" + run_vendor)

config.available_features.add("SWIFT_VERSION=" + swift_version)

if "optimized_stdlib" in config.available_features:
  config.available_features.add("optimized_stdlib_" + run_cpu)

swift_test_mode = lit_config.params.get('swift_test_mode', 'optimize_none')
swift_execution_tests_extra_flags = ''
if swift_test_mode == 'optimize_none':
    config.available_features.add("nonexecutable_test")
    config.available_features.add("executable_test")
    config.available_features.add("swift_test_mode_optimize_none")
    # Add the cpu as a feature so we can selectively disable tests in an
    # optimize mode for a cpu.
    config.available_features.add("swift_test_mode_optimize_none_" + run_cpu)
    swift_execution_tests_extra_flags = ''
elif swift_test_mode == 'optimize_none_with_implicit_dynamic':
    config.available_features.add("executable_test")
    config.limit_to_features.add("executable_test")
    config.available_features.add("swift_test_mode_optimize_none_with_implicit_dynamic")
    # Add the cpu as a feature so we can selectively disable tests in an
    # optimize mode for a cpu.
    config.available_features.add("swift_test_mode_optimize_none_" + run_cpu)
    swift_execution_tests_extra_flags = '-Xfrontend -enable-implicit-dynamic -Xfrontend -enable-private-imports -Xfrontend -enable-dynamic-replacement-chaining'
elif swift_test_mode == 'optimize_with_implicit_dynamic':
    config.available_features.add("executable_test")
    config.limit_to_features.add("executable_test")
    config.available_features.add("swift_test_mode_optimize_with_implicit_dynamic")
    # Add the cpu as a feature so we can selectively disable tests in an
    # optimize mode for a cpu.
    config.available_features.add("swift_test_mode_optimize_" + run_cpu)
    swift_execution_tests_extra_flags = '-O -Xfrontend -enable-implicit-dynamic -Xfrontend -enable-private-imports -Xfrontend -enable-dynamic-replacement-chaining'
elif swift_test_mode == 'optimize':
    config.available_features.add("executable_test")
    config.limit_to_features.add("executable_test")
    config.available_features.add("swift_test_mode_optimize")
    # Add the cpu as a feature so we can selectively disable tests in an
    # optimize mode for a cpu.
    config.available_features.add("swift_test_mode_optimize_" + run_cpu)
    swift_execution_tests_extra_flags = '-O'
elif swift_test_mode == 'optimize_size':
    config.available_features.add("executable_test")
    config.limit_to_features.add("executable_test")
    config.available_features.add("swift_test_mode_optimize_size")
    # Add the cpu as a feature so we can selectively disable tests in an
    # optimize mode for a cpu.
    config.available_features.add("swift_test_mode_optimize_" + run_cpu)
    swift_execution_tests_extra_flags = '-Osize'
elif swift_test_mode == 'optimize_unchecked':
    config.available_features.add("executable_test")
    config.limit_to_features.add("executable_test")
    config.available_features.add("swift_test_mode_optimize_unchecked")
    # Add the cpu as a feature so we can selectively disable tests in an
    # optimize mode for a cpu.
    config.available_features.add("swift_test_mode_optimize_unchecked_" + run_cpu)
    swift_execution_tests_extra_flags = '-Ounchecked'
elif swift_test_mode == 'only_executable':
    config.available_features.add("executable_test")
    config.limit_to_features.add("executable_test")
elif swift_test_mode == 'only_non_executable':
    config.available_features.add("nonexecutable_test")
else:
    lit_config.fatal("Unknown test mode %r" % swift_test_mode)

swift_test_subset = lit_config.params.get('swift_test_subset', 'validation')
if swift_test_subset in ['primary', 'validation', 'only_validation']:
    # No extra flags needed.
    pass
elif swift_test_subset == 'all':
    config.available_features.add("long_test")
    config.available_features.add("stress_test")
elif swift_test_subset == 'only_long':
    config.available_features.add("long_test")
    config.limit_to_features.add("long_test")
    config.limit_to_features.discard("executable_test")
elif swift_test_subset == 'only_stress':
    config.available_features.add("stress_test")
    config.limit_to_features.add("stress_test")
    config.limit_to_features.discard("executable_test")
else:
    lit_config.fatal("Unknown test mode %r" % swift_test_subset)

if 'swift_evolve' in lit_config.params:
    config.available_features.add("swift_evolve")

# Enable benchmark testing when the binary is found (has fully qualified path).
if config.benchmark_o != 'Benchmark_O':
    config.available_features.add('benchmark')

# Add substitutions for the run target triple, CPU, OS, and pointer size.
config.substitutions.append(('%target-triple', config.variant_triple))

if run_vendor == 'apple':
    if run_os == 'maccatalyst':
        config.stable_abi_triple = '%s-%s-ios13.0-macabi' % (run_cpu, run_vendor)
        config.pre_stable_abi_triple = config.stable_abi_triple
        config.next_stable_abi_triple = config.stable_abi_triple
        config.available_features.add('swift_stable_abi')
    else:
        # iOS 12.2 does not support 32-bit targets, so we cannot run tests that
        # want to deploy to an iOS that has Swift in the OS.
        if run_os == 'ios' and run_ptrsize == '32':
            pre_stable_version = '10'
        else:
            config.available_features.add('swift_stable_abi')
            PRE_STABLE_VERSION = {
                'macosx': '10.14.3',
                'ios': '12.1',
                'maccatalyst': '12.1',
                'tvos': '12.1',
                'watchos': '5.1'
            }
            pre_stable_version = PRE_STABLE_VERSION.get(run_os, '')

        config.pre_stable_abi_triple = '%s-%s-%s%s%s' % (run_cpu, run_vendor, run_os,
                                                         pre_stable_version, run_environment)
        STABLE_VERSION = {
            'macosx': '10.14.4',
            'ios': '12.2',
            'maccatalyst': '12.2',
            'tvos': '12.2',
            'watchos': '5.2'
        }
        stable_version = STABLE_VERSION.get(run_os, '')
        config.stable_abi_triple = '%s-%s-%s%s%s' % (run_cpu, run_vendor, run_os,
                                                     stable_version, run_environment)

        NEXT_STABLE_VERSION = {
            'macosx': '10.15',
            'ios': '13',
            'maccatalyst': '13',
            'tvos': '13',
            'watchos': '6'
        }
        next_stable_version = NEXT_STABLE_VERSION.get(run_os, '')
        config.next_stable_abi_triple = '%s-%s-%s%s%s' % (run_cpu, run_vendor, run_os,
                                                          next_stable_version, run_environment)

else:
    config.pre_stable_abi_triple = config.variant_triple
    config.stable_abi_triple = config.variant_triple
    config.next_stable_abi_triple = config.variant_triple

# On Apple platforms, this substitution names the maximum OS version *without*
# Swift in the OS. On non-Apple platforms this is equivalent to %target-triple.
config.substitutions.append(('%target-pre-stable-abi-triple',
                             config.pre_stable_abi_triple))

# On Apple platforms, this substitution names the minimum OS version with
# Swift 5.0 in the OS. On non-Apple platforms this is equivalent to %target-triple.
config.substitutions.append(('%target-stable-abi-triple',
                             config.stable_abi_triple))

# On Apple platforms, this substitution names the minimum OS version with
# Swift 5.1 in the OS, and an Objective-C runtime supporting class stubs.
config.substitutions.append(('%target-next-stable-abi-triple',
                             config.next_stable_abi_triple))

# Sanitizers are not supported on iOS7, yet all tests are configured to start
# testing with the earliest supported platform, which happens to be iOS7 for
# Swift.
# Setting target manually makes tests less versatile (a separate test is
# then required for each OS), thus instead we define a new environment
# variable which enforces the usage of iOS8+ when iOS is used.
config.substitutions.append(('%sanitizers-target-triple',
    config.variant_triple.replace("ios7", "ios8")))

config.substitutions.append(('%target-cpu', run_cpu))

target_os_abi = run_os
target_os_is_maccatalyst = "FALSE"
target_mandates_stable_abi = "FALSE"
if run_cpu in ('arm64e',):
  target_mandates_stable_abi = "TRUE"
  config.available_features.add('swift_only_stable_abi')
if run_os in ('maccatalyst',):
  # For purposes of ABI, treat maccatalyst as macosx since the maccatalyst ABI
  # must match the macosx ABI.
  target_os_abi = 'macosx'
  target_os_is_maccatalyst = "TRUE"
  config.available_features.add("OS=ios")
# macOS on ASi uses the stable ABI
if run_os in ('macosx',) and run_cpu in ('arm64',):
  target_mandates_stable_abi = "TRUE"
  config.available_features.add('swift_only_stable_abi')
if run_os in (
              'linux-android', 'linux-androideabi',             # Android
              'freebsd', 'openbsd',                             # BSD
              'linux-gnu', 'linux-gnueabihf',                   # Linux
              'windows-cygnus', 'windows-gnu', 'windows-msvc',  # Windows
             ):
  target_mandates_stable_abi = "TRUE"
  config.available_features.add('swift_only_stable_abi')
config.substitutions.append(('%target-os-abi', target_os_abi))
config.substitutions.append(('%target-os-is-maccatalyst', target_os_is_maccatalyst))
config.substitutions.append(('%target-mandates-stable-abi',
                               target_mandates_stable_abi))
config.substitutions.append(('%target-endian', run_endian))
config.substitutions.append(('%target-os', run_os))
config.substitutions.append(('%target-ptrsize', run_ptrsize))
config.substitutions.append(('%target-vendor', run_vendor))
config.substitutions.append(('%target-alignment', "%d" % (int(run_ptrsize)/8)))

# Enable Darwin SDK-dependent tests if we have an SDK.
# On Linux, assume that SDK path does not point to the Darwin SDK.
if config.variant_sdk != "":
  config.substitutions.append(('%sdk', '"%s"' % config.variant_sdk))

# Enable interpreter-based tests on platforms where the interpreter is known to
# work.
if platform.system() == 'Darwin' and (run_os == 'macosx' or run_os == 'darwin'):
    # Disable REPL tests if SDK overlay is not in the resource dir.
    # <rdar://problem/16678410> Adding more libraries with -lfoo to REPL is broken
    if swift_test_mode != 'only_non_executable':
      config.available_features.add('swift_repl')
      config.available_features.add('swift_interpreter')
elif platform.system() == 'Linux':
    if swift_test_mode != 'only_non_executable':
      config.available_features.add('swift_interpreter')

# The global environment in Android sets ANDROID_DATA, so if that variable is
# set, we are probably running in Android.
kIsAndroid = 'ANDROID_DATA' in os.environ

# swift-remoteast-test requires the ability to compile and run code
# for the system we compiled the swift-remoteast-test executable on.
# This is potentially a stronger constraint than just "can we interpret",
# but use that as an approximation for now.
if 'swift_interpreter' in config.available_features:
    config.available_features.add('swift-remoteast-test')

config.target_runtime = "unknown"

if (getattr(config, 'darwin_enable_maccatalyst', False) and
    config.darwin_maccatalyst_build_flavor == "ios-like"):
    variant_suffix = config.darwin_osx_variant_suffix
else:
    variant_suffix = config.variant_suffix
swift_reflection_test_name = 'swift-reflection-test' + variant_suffix

def use_interpreter_for_simple_runs():
    def make_simple_target_run(gyb=False, stdlib=False, parameterized=False):
        result = ''
        if gyb:
            result += ('%empty-directory(%t) && '
                       '%gyb %s -o %t/main.swift && '
                       '%line-directive %t/main.swift -- ')
        # FIXME: SWIFT_INTERPRETER needs to be a set of arguments, not just a
        # path.
        result += (
            'env SWIFT_INTERPRETER=%r %s %r %s -module-name main %s %s %s '
            % (config.swift, xcrun_prefix, config.swift, target_options,
               config.swift_test_options,
               config.swift_driver_test_options,
               swift_execution_tests_extra_flags))
        if stdlib:
            result += '-Xfrontend -disable-access-control '
        if parameterized:
            result += ' \\1 '
        if gyb:
            result += '%t/main.swift'
        else:
            result += '%s'
        return result
    config.target_run_stdlib_swiftgyb = make_simple_target_run(gyb=True)
    config.target_run_simple_swiftgyb = make_simple_target_run(gyb=True)
    config.target_run_stdlib_swift = make_simple_target_run(stdlib=True)
    config.target_run_simple_swift = make_simple_target_run()
    config.target_run_simple_swift_parameterized = make_simple_target_run(parameterized=True)
    config.target_run_simple_swiftgyb_parameterized = make_simple_target_run(gyb=True, parameterized=True)
    config.available_features.add('interpret')

target_specific_module_triple = config.variant_triple
target_future = target_specific_module_triple

config.target_run = ""

if run_vendor == 'apple':
    target_specific_module_triple = '{}-apple-{}'.format(
        { 'aarch64': 'arm64', 'amd64': 'x86_64' }.get(run_cpu, run_cpu),
        { 'macosx': 'macos', 'darwin': 'macos' }.get(run_os, run_os)
    )

    config.target_object_format = "macho"
    config.target_shared_library_prefix = 'lib'
    config.target_shared_library_suffix = ".dylib"
    config.target_codesign = "codesign -f -s -"
    config.target_runtime = "objc"

    config.available_features.add('libdispatch')
    config.available_features.add('foundation')
    config.available_features.add('objc_interop')

    xcrun_prefix = (
        "xcrun --toolchain %s --sdk %r" %
        (config.darwin_xcrun_toolchain, config.variant_sdk))
    extra_frameworks_dir = make_path(config.variant_sdk, "..", "..", "..",
                                     "Developer", "Library", "Frameworks")
    target_options = (
        "-target %s %s %s" %
        (config.variant_triple, resource_dir_opt, mcp_opt))
    target_options_for_mock_sdk = (
        "-target %s %s %s" %
        (config.variant_triple, stdlib_resource_dir_opt, mcp_opt))
    target_options_for_mock_sdk_after = sdk_overlay_dir_opt
    target_future_version = ''

    # Only permit non-executable tests for ARM on Darwin unless you are on macOS
    if 'arm' in run_cpu and run_os not in ('macosx',):
        if swift_test_mode != 'only_non_executable':
            raise RuntimeError('Device tests are currently only supported when '
            'the swift_test_mode is "only_non_executable". Current '
            'swift_test_mode is {}.'.format(swift_test_mode))

    if 'arm' in run_cpu and not (run_os == 'macosx' or run_os == 'maccatalyst'):
       # iOS/tvOS/watchOS device
       if run_os == 'ios':
           lit_config.note('Testing iOS ' + config.variant_triple)
           xcrun_sdk_name = "iphoneos"
           target_future_version = "99.0"
       elif run_os == 'tvos':
           lit_config.note('Testing AppleTV ' + config.variant_triple)
           xcrun_sdk_name = "appletvos"
           target_future_version = "99.0"
       elif run_os == 'watchos':
           lit_config.note('Testing watchOS ' + config.variant_triple)
           xcrun_sdk_name = "watchos"
           target_future_version = "9.99.0"

       config.target_cc_options = (
           "-arch %s -m%s-version-min=%s %s" %
           (run_cpu, run_os, run_vers, clang_mcp_opt))

       config.target_build_swift = (
           ("%s %s %s -F %r -toolchain-stdlib-rpath " +
            "-Xlinker -rpath -Xlinker %r " +
            "-Xlinker -rpath -Xlinker /usr/lib/swift " +
            "%s %s %s %s") %
           (xcrun_prefix, config.swiftc, target_options,
            extra_frameworks_dir,
            "/tmp/swifttest-device/lib",
            sdk_overlay_linker_opt, config.swift_test_options,
            config.swift_driver_test_options,
            swift_execution_tests_extra_flags))
       config.target_run = "unsupported"

       (sw_vers_name, sw_vers_vers, sw_vers_build) = \
            darwin_get_sdk_version(config.variant_sdk)

    elif run_os == 'ios' or run_os == 'tvos' or run_os == 'watchos':
        # iOS/tvOS/watchOS simulator
        if run_os == 'ios':
            config.available_features.add('DARWIN_SIMULATOR=ios')
            lit_config.note("Testing iOS simulator " + config.variant_triple)
            xcrun_sdk_name = "iphonesimulator"
            target_future_version = "99.0"
        elif run_os == 'watchos':
            config.available_features.add('DARWIN_SIMULATOR=watchos')
            lit_config.note("Testing watchOS simulator " + config.variant_triple)
            xcrun_sdk_name = "watchsimulator"
            target_future_version = "9.99.0"
        else:
            config.available_features.add('DARWIN_SIMULATOR=tvos')
            lit_config.note("Testing AppleTV simulator " + config.variant_triple)
            xcrun_sdk_name = "appletvsimulator"
            target_future_version = "99.0"

        target_specific_module_triple += "-simulator"

        config.target_cc_options = (
            "-arch %s -m%s-simulator-version-min=%s %s" %
            (run_cpu, run_os, run_vers, clang_mcp_opt))

        config.target_build_swift = (
            ("%s %s %s -F %r -toolchain-stdlib-rpath %s " +
             "-Xlinker -rpath -Xlinker /usr/lib/swift " +
             " %s %s %s") %
            (xcrun_prefix, config.swiftc, target_options,
             extra_frameworks_dir,
             sdk_overlay_linker_opt, config.swift_test_options,
             config.swift_driver_test_options,
             swift_execution_tests_extra_flags))
        # FIXME: allow specification of simulator and version
        #
        # Note: don't pass '--adopt-pid' to sim.  This can trigger a kernel
        # panic.
        # <rdar://problem/11806093> multithreaded 64-to-32 exec is broken
        # (foundation tool launched with sim --adopt-pid occasionally
        # segmentation faults)
        config.target_run = (
            "%s %s " %
            (xcrun_prefix, get_simulator_command(run_os, run_cpu, config.variant_sdk)))

        (sw_vers_name, sw_vers_vers, sw_vers_build) = \
            darwin_get_sdk_version(config.variant_sdk)

        if (sw_vers_name == '' or sw_vers_vers == '' or sw_vers_build == ''):
            lit_config.fatal('Could not get or decode sw_vers output. ' +
                             'Perhaps the simulator is not working.')

    elif run_os == 'macosx' or run_os == 'maccatalyst':
        # OS X
        lit_config.note("Testing OS X " + config.variant_triple)

        xcrun_sdk_name = "macosx"

        if run_os == 'maccatalyst':
            # For maccatalyst, pass the target triple to clang
            # rather than arch and version separately.
            config.target_cc_options = (
                "-target %s %s" %
                (config.variant_triple, clang_mcp_opt))
        else:
            config.target_cc_options = (
                "-arch %s -m%s-version-min=%s %s" %
                (run_cpu, run_os, run_vers, clang_mcp_opt))

        maccatalyst_frameworks_component = ""
        if run_os == 'maccatalyst':
            # Additional framework search paths for macCatalyst.
            # These have to come before other search paths so that for
            # unzippered twin frameworks the unzippered twin version
            # is favored under macCatalyst.
          maccatalyst_frameworks_dir = make_path(config.variant_sdk,
                 "System", "iOSSupport", "System", "Library", "Frameworks")
          maccatalyst_frameworks_component = ( "-F %r" % maccatalyst_frameworks_dir )
            # Module triples end in ios-macabi.
          target_specific_module_triple = '{}-apple-ios-macabi'.format(
              { 'aarch64': 'arm64', 'amd64': 'x86_64' }.get(run_cpu, run_cpu)
          )

        config.target_build_swift = (
            ("%s %s %s %s -F %r -toolchain-stdlib-rpath "
             + "-Xlinker -rpath -Xlinker %r "
             + "-Xlinker -rpath -Xlinker /usr/lib/swift "
             + "%s %s %s %s "
             + "-F %r -Xlinker -rpath -Xlinker %r")
            % (xcrun_prefix, config.swiftc, target_options,
               maccatalyst_frameworks_component,
               extra_frameworks_dir, extra_frameworks_dir,
               sdk_overlay_linker_opt, config.swift_test_options,
               config.swift_driver_test_options,
               swift_execution_tests_extra_flags, sourcekitd_framework_dir,
               sourcekitd_framework_dir))

        config.target_run = ""
        target_future_version = "99.99"

        if 'interpret' in lit_config.params:
            use_interpreter_for_simple_runs()

        (sw_vers_name, sw_vers_vers, sw_vers_build) = \
            darwin_get_sw_vers()

    else:
        lit_config.fatal("Unknown Apple OS '" + run_os + "' " +
                         "(from " + config.variant_triple + ")")

    lit_config.note(
        'Running tests on %s version %s (%s)' %
        (sw_vers_name, sw_vers_vers, sw_vers_build))

    config.target_sdk_name = xcrun_sdk_name
    config.target_ld = "%s ld -L%r" % (xcrun_prefix, make_path(test_resource_dir, config.target_sdk_name))

    maccatalyst_extra_frameworks = ""
    if run_os == 'maccatalyst':
        maccatalyst_extra_frameworks = "-F {}/System/iOSSupport/System/Library/Frameworks".format(config.variant_sdk)
    config.target_swift_frontend = (
        "%s %s -sdk %r %s %s %s" %
        (config.swift_frontend, target_options, config.variant_sdk, maccatalyst_extra_frameworks,
         config.swift_test_options, config.swift_frontend_test_options))
    subst_target_swift_frontend_mock_sdk = (
        "%s %s -sdk %r %s %s" %
        (config.swift_frontend, target_options_for_mock_sdk, config.variant_sdk,
         config.swift_test_options, config.swift_frontend_test_options))
    config.target_swift_modulewrap = (
        '%s -modulewrap -target %s' %
        (config.swiftc, config.variant_triple))
    config.target_swift_emit_pcm = (
        '%s -emit-pcm -target %s' %
        (config.swiftc, config.variant_triple))
    subst_target_swift_frontend_mock_sdk_after = \
        target_options_for_mock_sdk_after
    config.target_sil_opt = (
        "%s %s %s %s" %
        (xcrun_prefix, config.sil_opt, target_options, config.sil_test_options))
    subst_target_sil_opt_mock_sdk = (
        "%s %s" %
        (config.sil_opt, target_options_for_mock_sdk))
    subst_target_sil_opt_mock_sdk_after = \
        target_options_for_mock_sdk_after
    config.target_swift_symbolgraph_extract = (
        "%s %s %s" %
        (xcrun_prefix, config.swift_symbolgraph_extract, target_options))
    config.target_swift_ide_test = (
        "%s %s %s %s" %
        (xcrun_prefix, config.swift_ide_test, target_options, ccp_opt))
    subst_target_swift_ide_test_mock_sdk = (
        "%s %s %s %s" %
        (xcrun_prefix, config.swift_ide_test, target_options_for_mock_sdk, ccp_opt))
    subst_target_swift_ide_test_mock_sdk_after = \
        target_options_for_mock_sdk_after
    config.target_swiftc_driver = (
        ("%s %s -toolchain-stdlib-rpath %s " +
         "-Xlinker -rpath -Xlinker /usr/lib/swift ")%
        (xcrun_prefix, config.swiftc, target_options))
    config.target_clang = (
        "%s clang++ %s" %
        (xcrun_prefix, config.target_cc_options))

    config.target_build_swift_dylib = (
        "%s -parse-as-library -emit-library -o '\\1' "
        "-Xlinker -install_name -Xlinker @executable_path/$(basename '\\1')"
        % (config.target_build_swift))
    config.target_add_rpath = r'-Xlinker -rpath -Xlinker \1'

    target_future = format('%s-apple-%s%s%s' % (run_cpu, run_os, target_future_version, run_environment))

    config.otool_classic = ("%s otool-classic" % (xcrun_prefix))

elif run_os in ['windows-msvc']:
    lit_config.note('Testing Windows ' + config.variant_triple)
    config.environment['NUMBER_OF_PROCESSORS'] = os.environ['NUMBER_OF_PROCESSORS']
    if 'PROCESSOR_ARCHITEW6432' in os.environ:
        config.environment['PROCESSOR_ARCHITEW6432'] = os.environ['PROCESSOR_ARCHITEW6432']
    if 'PROCESSOR_ARCHITECTURE' in os.environ:
        config.environment['PROCESSOR_ARCHITECTURE'] = os.environ['PROCESSOR_ARCHITECTURE']
    if 'PROCESSOR_IDENTIFIER' in os.environ:
        config.environment['PROCESSOR_IDENTIFIER'] = os.environ['PROCESSOR_IDENTIFIER']
    config.environment['PYTHON_EXECUTABLE'] = sys.executable
    config.target_object_format = 'coff'
    config.target_shared_library_prefix = ''
    config.target_shared_library_suffix = '.dll'
    config.target_sdk_name = 'windows'
    config.target_runtime = 'native'
    config.target_cc_options = ""

    config.target_build_swift =                                                  \
            ('%r -target %s %s %s %s %s -libc %s' %                              \
                    (config.swiftc, config.variant_triple, resource_dir_opt,     \
                     config.swift_test_options, config.swift_driver_test_options,\
                     swift_execution_tests_extra_flags,                          \
                     config.swift_stdlib_msvc_runtime))

    config.target_run = ''

    config.target_swift_frontend =                                               \
            ('%r -target %s %s %s %s %s' % (config.swift_frontend,             \
                                                      config.variant_triple,     \
                                                      resource_dir_opt, mcp_opt, \
                                                      config.swift_test_options, \
                                                      config.swift_frontend_test_options))

    config.target_codesign = 'echo'

    subst_target_swift_frontend_mock_sdk = config.target_swift_frontend
    subst_target_swift_frontend_mock_sdk_after = ''

    config.target_build_swift_dylib =                                            \
            SubstituteCaptures("%s -parse-as-library -emit-library -o \\1" % (config.target_build_swift))
    config.target_add_rpath = r''

    config.target_clang =                                                        \
            ('clang++ -target %s %s %s -fobjc-runtime=ios-5.0' %                 \
             (config.variant_triple, clang_mcp_opt, config.target_cc_options))
    config.target_ld =                                                           \
            ('%r -libpath:%s' % (config.link, os.path.join(test_resource_dir,    \
                                                           config.target_sdk_name)))
    config.target_sil_opt =                                                      \
            ('%r -target %s %s %s %s' % (config.sil_opt, config.variant_triple,  \
                                         resource_dir_opt, mcp_opt,              \
                                         config.sil_test_options))
    subst_target_sil_opt_mock_sdk = config.target_sil_opt
    subst_target_sil_opt_mock_sdk_after = ''
    config.target_swift_symbolgraph_extract =                                    \
            ('%r -target %s %s' % (config.swift_symbolgraph_extract,             \
                                         config.variant_triple,                  \
                                         mcp_opt))
    config.target_swift_ide_test =                                               \
            ('%r -target %s %s %s %s' % (config.swift_ide_test,                  \
                                         config.variant_triple,                  \
                                         resource_dir_opt, mcp_opt, ccp_opt))

    subst_target_swift_ide_test_mock_sdk = config.target_swift_ide_test
    subst_target_swift_ide_test_mock_sdk_after = ''

    config.target_swiftc_driver =                                                \
            ('%r -target %s %s %s' % (config.swiftc, config.variant_triple,      \
                                      resource_dir_opt, mcp_opt))
    config.target_swift_modulewrap =                                             \
            ('%r -modulewrap -target %s' % (config.swiftc, config.variant_triple))
    config.target_swift_emit_pcm =                                               \
            ('%r -emit-pcm -target %s' % (config.swiftc, config.variant_triple))


elif (run_os in ['linux-gnu', 'linux-gnueabihf', 'freebsd', 'openbsd', 'windows-cygnus', 'windows-gnu'] or
      (kIsAndroid and run_os in ['linux-android', 'linux-androideabi'])):
      # Running lit and the compiler on Android itself is more like running on Linux,
      # ie the NDK and adb aren't needed, so use this instead.
    # Linux/FreeBSD/Cygwin/Android
    if run_os == 'windows-cygnus':
      lit_config.note("Testing Cygwin " + config.variant_triple)
      config.target_object_format = "coff"
      config.target_shared_library_prefix = 'lib'
      config.target_shared_library_suffix = ".dll"
      config.target_sdk_name = "cygwin"
      config.target_cc_options = ""
    elif run_os == 'windows-gnu':
      lit_config.note("Testing MinGW " + config.variant_triple)
      config.target_object_format = "coff"
      config.target_shared_library_prefix = 'lib'
      config.target_shared_library_suffix = ".dll"
      config.target_sdk_name = "mingw"
      config.target_cc_options = ""
    elif run_os == 'freebsd':
      lit_config.note("Testing FreeBSD " + config.variant_triple)
      config.target_object_format = "elf"
      config.target_shared_library_prefix = 'lib'
      config.target_shared_library_suffix = ".so"
      config.target_sdk_name = "freebsd"
      config.target_cc_options = "-fPIE"
    elif run_os == 'openbsd':
      lit_config.note("Testing OpenBSD " + config.variant_triple)
      config.target_object_format = "elf"
      config.target_shared_library_prefix = 'lib'
      config.target_shared_library_suffix = ".so"
      config.target_sdk_name = "openbsd"
      config.target_cc_options = "-fPIE"
    elif kIsAndroid:
      lit_config.note("Testing Android " + config.variant_triple)
      config.target_object_format = "elf"
      config.target_shared_library_prefix = 'lib'
      config.target_shared_library_suffix = ".so"
      config.target_sdk_name = "android"
      # Needed by several ParseableInterface/swift_build_sdk_interfaces tests on
      # Android
      config.environment['ANDROID_DATA'] = os.environ['ANDROID_DATA']
      config.target_cc_options = "-fPIE"
    else:
      lit_config.note("Testing Linux " + config.variant_triple)
      config.target_object_format = "elf"
      config.target_shared_library_prefix = 'lib'
      config.target_shared_library_suffix = ".so"
      config.target_sdk_name = "linux"
      config.target_cc_options = "-fPIE"
    config.target_runtime = "native"
    config.target_swift_autolink_extract = inferSwiftBinary("swift-autolink-extract")

    libdispatch_artifact_dir = config.libdispatch_build_path
    libdispatch_swift_module_dir = make_path(libdispatch_artifact_dir, 'src', 'swift', 'swift')
    libdispatch_artifacts = [
        make_path(libdispatch_artifact_dir, 'libdispatch.so'),
        make_path(libdispatch_artifact_dir, 'libswiftDispatch.so'),
        make_path(libdispatch_swift_module_dir, 'Dispatch.swiftmodule')]
    if (all(os.path.exists(p) for p in libdispatch_artifacts)):
        config.available_features.add('libdispatch')
        config.libdispatch_artifact_dir = libdispatch_artifact_dir
        libdispatch_source_dir = make_path(config.swift_src_root, os.pardir, 'swift-corelibs-libdispatch')
        config.import_libdispatch = ('-I %s -I %s -L %s'
            % (libdispatch_source_dir, libdispatch_swift_module_dir, libdispatch_artifact_dir))

    config.target_build_swift = (
        '%s -target %s -toolchain-stdlib-rpath %s %s %s %s %s'
        % (config.swiftc, config.variant_triple, resource_dir_opt, mcp_opt,
           config.swift_test_options, config.swift_driver_test_options,
           swift_execution_tests_extra_flags))
    config.target_codesign = "echo"
    config.target_build_swift_dylib = (
        "%s -parse-as-library -emit-library -o '\\1'"
        % (config.target_build_swift))
    config.target_add_rpath = r'-Xlinker -rpath -Xlinker \1'
    config.target_swift_frontend = (
        '%s -target %s %s %s %s %s '
        % (config.swift_frontend, config.variant_triple, resource_dir_opt, mcp_opt,
        config.swift_test_options, config.swift_frontend_test_options))
    subst_target_swift_frontend_mock_sdk = config.target_swift_frontend
    subst_target_swift_frontend_mock_sdk_after = ""
    config.target_run = ''
    if 'interpret' in lit_config.params:
        use_interpreter_for_simple_runs()
    config.target_sil_opt = (
        '%s -target %s %s %s %s' %
        (config.sil_opt, config.variant_triple, resource_dir_opt, mcp_opt, config.sil_test_options))
    subst_target_sil_opt_mock_sdk = config.target_sil_opt
    subst_target_sil_opt_mock_sdk_after = ""
    config.target_swift_symbolgraph_extract = (
        '%s -target %s %s' %
        (config.swift_symbolgraph_extract, config.variant_triple, mcp_opt))
    config.target_swift_ide_test = (
        '%s -target %s %s %s %s' %
        (config.swift_ide_test, config.variant_triple, resource_dir_opt,
         mcp_opt, ccp_opt))
    subst_target_swift_ide_test_mock_sdk = config.target_swift_ide_test
    subst_target_swift_ide_test_mock_sdk_after = ""
    config.target_swiftc_driver = (
        "%s -target %s -toolchain-stdlib-rpath %s %s" %
        (config.swiftc, config.variant_triple, resource_dir_opt, mcp_opt))
    config.target_swift_modulewrap = (
        '%s -modulewrap -target %s' %
        (config.swiftc, config.variant_triple))
    config.target_swift_emit_pcm = (
        '%s -emit-pcm -target %s' %
        (config.swiftc, config.variant_triple))
    config.target_clang = (
        "clang++ -target %s %s %s -fobjc-runtime=ios-5.0" %
        (config.variant_triple, clang_mcp_opt, config.target_cc_options))
    config.target_ld = "ld -L%r" % (make_path(test_resource_dir, config.target_sdk_name))
elif run_os == 'linux-androideabi' or run_os == 'linux-android':
    # The module triple for Android ARMv7 seems to be canonicalized in LLVM
    # to be armv7-none-linux-android, without the "eabi" bit. Let's remove the
    # same bit from the substitutions so the tests pass correctly.
    target_specific_module_triple = re.sub(r'androideabi', 'android',
                                           target_specific_module_triple)
    config.variant_triple = re.sub(r'androideabi', 'android', config.variant_triple)
    config.target_cc_options = "-fPIE"
    def get_architecture_value(**kwargs):
        result = kwargs[run_cpu]
        if result is None:
          if run_cpu.startswith("armv7"):
            result = kwargs["armv7"]
          elif run_cpu == "arm64":
            result = kwards["aarch64"]
        return result

    ndk_platform_tuple = get_architecture_value(armv7="armeabi-v7a",
                                                aarch64="arm64-v8a")
    ndk_platform_triple = get_architecture_value(armv7="arm-linux-androideabi",
                                                 aarch64="aarch64-linux-android")
    toolchain_directory_name = "{}-{}".format(ndk_platform_triple, config.android_ndk_gcc_version)
    if platform.system() == 'Linux':
        prebuilt_directory = 'linux-x86_64'
    elif platform.system() == 'Darwin':
        prebuilt_directory = 'darwin-x86_64'
    elif platform.system() == 'Windows':
        # TODO: NDK distributes for Windows 32 and 64 bits. platform.machine()
        # should allow us to find out the word size, but I don't have a
        # machine to test right now. I think the values are AMD64 and x86, but
        # I'm not sure. Everybody gets the 64 bits version for now.
        prebuilt_directory = 'windows-x86_64'

    toolchain_directory = make_path(
        config.android_ndk_path, "toolchains", toolchain_directory_name,
        "prebuilt", prebuilt_directory)
    tools_directory = pipes.quote(make_path(
        toolchain_directory, ndk_platform_triple, "bin"))
    lit_config.note("Testing Android " + config.variant_triple)
    config.target_object_format = "elf"
    config.target_shared_library_prefix = 'lib'
    config.target_shared_library_suffix = ".so"
    config.target_runtime = "native"
    config.target_swift_autolink_extract = inferSwiftBinary("swift-autolink-extract")
    config.target_sdk_name = "android"
    android_link_paths_opt = "-L {} -L {} -L {}".format(
        pipes.quote(make_path(
            config.android_ndk_path, "sources", "cxx-stl", "llvm-libc++",
            "libs", ndk_platform_tuple)),
        pipes.quote(make_path(
            toolchain_directory, "lib", "gcc", ndk_platform_triple,
            "{}.x".format(config.android_ndk_gcc_version))),
        pipes.quote(make_path(
            toolchain_directory, ndk_platform_triple, "lib")))
    # Since NDK r14 the headers are unified under $NDK_PATH/sysroot, so the -sdk
    # switch is not enough. Additionally we have to include both the unified
    # sysroot, and the architecture sysroot.
    unified_android_include_path = pipes.quote(make_path(
        config.android_ndk_path, "sysroot", "usr", "include"))
    architecture_android_include_path = pipes.quote(make_path(
        config.android_ndk_path, "sysroot", "usr", "include",
        ndk_platform_triple))
    android_include_paths_opt = "-I {} -I {}".format(
        unified_android_include_path, architecture_android_include_path)
    # clang can use -isystem, but Swift cannot.
    android_include_system_paths_opt = "-isystem {} -isystem {}".format(
        unified_android_include_path, architecture_android_include_path)
    config.target_build_swift = ' '.join([
        config.swiftc,
        '-target', config.variant_triple,
        '-Xcc', '--sysroot={}'.format(config.variant_sdk),
        '-Xclang-linker', '--sysroot={}'.format(config.variant_sdk),
        '-tools-directory', tools_directory,
        android_include_paths_opt, android_link_paths_opt,
        '-use-ld=%s' % config.android_linker_name,
        resource_dir_opt, mcp_opt, config.swift_test_options,
        config.swift_driver_test_options, swift_execution_tests_extra_flags])
    config.target_codesign = "echo"
    config.target_build_swift_dylib = ' '.join([
        config.target_build_swift,
        '-parse-as-library', '-emit-library',
        '-o', "'\\1'"])
    config.target_add_rpath = r'-Xlinker -rpath -Xlinker \1'
    config.target_swift_frontend = ' '.join([
        config.swift_frontend,
        '-target', config.variant_triple,
        android_include_paths_opt, android_link_paths_opt,
        resource_dir_opt, mcp_opt, config.swift_test_options,
        config.swift_frontend_test_options])
    subst_target_swift_frontend_mock_sdk = config.target_swift_frontend
    subst_target_swift_frontend_mock_sdk_after = ""
    config.target_run = make_path(config.swift_src_root, 'utils', 'android', 'adb_test_runner.py')
    # FIXME: Include -sdk in this invocation.
    config.target_sil_opt = ' '.join([
        config.sil_opt,
        '-target', config.variant_triple,
        android_include_paths_opt,
        resource_dir_opt, mcp_opt, config.sil_test_options])
    subst_target_sil_opt_mock_sdk = config.target_sil_opt
    subst_target_sil_opt_mock_sdk_after = ""
    config.target_swift_symbolgraph_extract = ' '.join([
        config.swift_symbolgraph_extract,
        '-target', config.variant_triple,
        mcp_opt])
    config.target_swift_ide_test = ' '.join([
        config.swift_ide_test,
        '-target', config.variant_triple,
        resource_dir_opt, mcp_opt, ccp_opt])
    subst_target_swift_ide_test_mock_sdk = config.target_swift_ide_test
    subst_target_swift_ide_test_mock_sdk_after = ""
    config.target_swiftc_driver = ' '.join([
        config.swiftc,
        '-target', config.variant_triple,
        '-toolchain-stdlib-rpath',
        '-Xcc', '--sysroot={}'.format(config.variant_sdk),
        '-Xclang-linker', '--sysroot={}'.format(config.variant_sdk),
        '-tools-directory', tools_directory,
        android_link_paths_opt, resource_dir_opt, mcp_opt,
        '-use-ld=%s' % config.android_linker_name])
    config.target_swift_modulewrap = ' '.join([
        config.swiftc, '-modulewrap',
        '-target', config.variant_triple])
    config.target_swift_emit_pcm = ' '.join([
        config.swiftc, '-emit-pcm',
        '-target', config.variant_triple])
    config.target_clang = ' '.join([
        'clang++',
        '-target', config.variant_triple,
        clang_mcp_opt, android_include_system_paths_opt,
        config.target_cc_options, '-fobjc-runtime=ios-5.0'])
    config.target_ld = ' '.join([
        tools_directory,
        '-L%s' % make_path(test_resource_dir, config.target_sdk_name)])
    # The Swift interpreter is not available when targeting Android.
    config.available_features.discard('swift_interpreter')
elif run_os == 'wasi':
    lit_config.note("Testing WebAssembly/WASI " + config.variant_triple)

    config.target_object_format = "wasm"
    config.target_shared_library_prefix = 'lib'
    config.target_shared_library_suffix = ".a"
    config.target_sdk_name = "wasi"
    config.target_runtime = "native"

    config.target_swift_autolink_extract = inferSwiftBinary("swift-autolink-extract")

    config.target_build_swift = ' '.join([
        config.swiftc,
        '-target', config.variant_triple,
        '-Xcc', '--sysroot=%s' % config.variant_sdk,
        '-Xclang-linker', '--sysroot=%s' % config.variant_sdk,
        '-toolchain-stdlib-rpath', resource_dir_opt,
        mcp_opt, config.swift_test_options,
        config.swift_driver_test_options, swift_execution_tests_extra_flags])
    config.target_codesign = "echo"
    config.target_build_swift_dylib = (
        "%s -parse-as-library -emit-library -o '\\1'"
        % (config.target_build_swift))
    config.target_add_rpath = ''
    config.target_swift_frontend = ' '.join([
        config.swift_frontend,
        '-target', config.variant_triple,
        '-Xcc', '--sysroot=%s' % config.variant_sdk,
        resource_dir_opt, mcp_opt,
        config.swift_test_options, config.swift_frontend_test_options])
    subst_target_swift_frontend_mock_sdk = config.target_swift_frontend
    subst_target_swift_frontend_mock_sdk_after = ""
    config.target_run = '%s run --backend cranelift --' % config.wasmer
    if 'interpret' in lit_config.params:
        use_interpreter_for_simple_runs()
    config.target_sil_opt = (
        '%s -target %s %s %s %s' %
        (config.sil_opt, config.variant_triple, resource_dir_opt, mcp_opt, config.sil_test_options))
    config.target_swift_symbolgraph_extract = ' '.join([
        config.swift_symbolgraph_extract,
        '-target', config.variant_triple,
        mcp_opt])
    config.target_swift_ide_test = (
        '%s -target %s %s %s %s' %
        (config.swift_ide_test, config.variant_triple, resource_dir_opt,
         mcp_opt, ccp_opt))
    subst_target_swift_ide_test_mock_sdk = config.target_swift_ide_test
    subst_target_swift_ide_test_mock_sdk_after = ""
    config.target_swiftc_driver = (
        "%s -target %s -toolchain-stdlib-rpath %s %s" %
        (config.swiftc, config.variant_triple, resource_dir_opt, mcp_opt))
    config.target_swift_modulewrap = (
        '%s -modulewrap -target %s' %
        (config.swiftc, config.variant_triple))
    config.target_swift_emit_pcm = (
        '%s -emit-pcm -target %s' %
        (config.swiftc, config.variant_triple))
    config.target_clang = (
        "%s -target %s %s -fobjc-runtime=ios-5.0" %
        (config.clang, config.variant_triple, clang_mcp_opt))
    config.target_ld = (
        "%s -L%r" %
        (config.wasm_ld, make_path(test_resource_dir, config.target_sdk_name)))

    # The Swift interpreter is not available when targeting WebAssembly/WASI.
    config.available_features.discard('swift_interpreter')

else:
    lit_config.fatal("Don't know how to define target_run and "
                     "target_build_swift for platform " + config.variant_triple)

config.swift_api_digester = (
    '%s -target %s' % (config.swift_api_digester, config.variant_triple))
config.substitutions.append(('%api-digester', config.swift_api_digester))

# Enable typo-correction for testing purposes.
config.target_swift_frontend += " -typo-correction-limit 10 "
subst_target_swift_frontend_mock_sdk += " -typo-correction-limit 10 "

config.substitutions.append(('%module-target-triple',
                             target_specific_module_triple))
config.substitutions.append(('%module-target-future', target_future))

# Add 'target-sdk-name' as the name for platform-specific directories
config.substitutions.append(('%target-sdk-name', config.target_sdk_name))

# Add 'stdlib_dir' as the path to the stdlib resource directory
stdlib_dir = os.path.join(config.swift_lib_dir, "swift")
if platform.system() == 'Darwin':
    if run_os == 'maccatalyst':
        stdlib_dir = os.path.join(stdlib_dir, run_os)
    else:
        stdlib_dir = os.path.join(stdlib_dir, config.target_sdk_name)
else:
    stdlib_dir = os.path.join(stdlib_dir, config.target_sdk_name, target_arch)
config.substitutions.append(('%stdlib_dir', stdlib_dir))

# Add 'stdlib_module' as the path to the stdlib .swiftmodule file
stdlib_module = os.path.join(stdlib_dir, "Swift.swiftmodule")
if platform.system() == 'Darwin':
    stdlib_module = os.path.join(stdlib_module, target_specific_module_triple + ".swiftmodule")
config.substitutions.append(('%stdlib_module', stdlib_module))
config.substitutions.append(('%/stdlib_module',
                             '/'.join(os.path.normpath(stdlib_module).split(os.sep))))

# Add 'ononesupport_module' as the path to the SwiftOnoneSupport .swiftmodule file
ononesupport_module = os.path.join(stdlib_dir, "SwiftOnoneSupport.swiftmodule")
if platform.system() == 'Darwin':
    ononesupport_module = os.path.join(ononesupport_module, target_specific_module_triple + ".swiftmodule")
config.substitutions.append(('%ononesupport_module', ononesupport_module))
config.substitutions.append(('%/ononesupport_module',
                             '/'.join(os.path.normpath(ononesupport_module).split(os.sep))))

# Different OS's require different prefixes for the environment variables to be
# propagated to the calling contexts.
# In order to make tests OS-agnostic, names of environment variables should be
# prefixed with `%env-`, which is then expanded to the appropriate prefix.
SIMULATOR_ENV_PREFIX = 'SIMCTL_CHILD_'
ENV_VAR_PREFIXES = {
    'iphonesimulator': SIMULATOR_ENV_PREFIX,
    'watchsimulator': SIMULATOR_ENV_PREFIX,
    'appletvsimulator': SIMULATOR_ENV_PREFIX,
    'android': 'ANDROID_CHILD_'
}
TARGET_ENV_PREFIX = ENV_VAR_PREFIXES.get(config.target_sdk_name, "") if not kIsAndroid else ""

if 'remote_run_host' in lit_config.params:
    if 'remote_run_tmpdir' not in lit_config.params:
        lit_config.fatal("'remote_run_host' provided, but no "
                         "'remote_run_tmpdir'")

    remote_run_host = lit_config.params['remote_run_host']
    remote_tmp_dir = lit_config.params['remote_run_tmpdir']
    remote_lib_dir = os.path.join(remote_tmp_dir, 'stdlib')
    remote_run_lib_path = ''
    if 'use_os_stdlib' not in lit_config.params:
        remote_run_lib_path = remote_lib_dir
    else:
        config.available_features.add('use_os_stdlib')
        os_stdlib_path = ''
        if run_vendor == 'apple':
            #If we get swift-in-the-OS for non-Apple platforms, add a condition here
            os_stdlib_path = "/usr/lib/swift"
        remote_run_lib_path = os.path.pathsep.join((os_stdlib_path, remote_lib_dir))

    remote_run_extra_args_param = lit_config.params.get('remote_run_extra_args')
    remote_run_extra_args = shlex.split(remote_run_extra_args_param or '')
    if 'remote_run_identity' in lit_config.params:
        remote_run_identity = lit_config.params['remote_run_identity']
        remote_run_extra_args += ['-i', remote_run_identity]

    if 'remote_run_skip_upload_stdlib' not in lit_config.params:
        lit_config.note(
            "Uploading resources to {0} on {1}".format(remote_lib_dir,
                                                       remote_run_host))

        def upload_files(files, input_prefix, remote_input_prefix):
            subprocess.check_call(
                [
                    os.path.join(config.swift_utils, 'remote-run'),
                    '--remote-dir', remote_tmp_dir,
                    '--input-prefix', input_prefix,
                    '--remote-input-prefix', remote_input_prefix
                ] + remote_run_extra_args + [
                    remote_run_host,
                    '--',
                    'true' # A dummy command that ignores its arguments.
                ] + files)

        def upload_dylibs(dylib_dir):
            glob_pattern = os.path.join(dylib_dir,
                                        '*' + config.target_shared_library_suffix)
            libs = glob.glob(glob_pattern)
            upload_files(libs, dylib_dir, 'stdlib/')

        upload_dylibs(os.path.join(test_resource_dir, config.target_sdk_name))
        # FIXME: This could be more principled.
        upload_dylibs(os.path.join(test_resource_dir, "clang", "lib", "darwin"))
        upload_dylibs(os.path.join(test_resource_dir, "clang", "lib", "linux"))

        # FIXME: Uploading specific files in bin/ is not very scalable.
        local_swift_reflection_test = lit.util.which(
            swift_reflection_test_name, config.environment['PATH'])
        upload_files([local_swift_reflection_test],
                     os.path.dirname(local_swift_reflection_test),
                     'bin/')

    config.target_run = (
        "/usr/bin/env "
        "REMOTE_RUN_CHILD_DYLD_LIBRARY_PATH='{0}' " # Apple option
        "REMOTE_RUN_CHILD_LD_LIBRARY_PATH='{0}' " # Linux option
        "'{1}'/remote-run --input-prefix '{2}' --output-prefix %t "
        "--remote-dir '{3}'%t {4} {5}".format(remote_run_lib_path,
                                              config.swift_utils,
                                              config.swift_src_root,
                                              remote_tmp_dir,
                                              ' '.join(remote_run_extra_args),
                                              remote_run_host))
    config.target_swift_reflection_test = os.path.join(
        remote_tmp_dir, 'bin', swift_reflection_test_name)
    TARGET_ENV_PREFIX = 'REMOTE_RUN_CHILD_'
    config.available_features.add('remote_run')

config.substitutions.append(('%env-', TARGET_ENV_PREFIX))
config.substitutions.append(("%target-sdk-name", config.target_sdk_name))

simulator_sdks = [
    'iphonesimulator',
    'watchsimulator',
    'appletvsimulator'
]
if config.target_sdk_name in simulator_sdks:
    config.substitutions.append(('%target-is-simulator', 'true'))
else:
    config.substitutions.append(('%target-is-simulator', 'false'))


config.compiler_rt_libs = []
config.compiler_rt_platform = {
    'iphoneos': 'ios',
    'appletvos': 'tvos',
    'watchos': 'watchos',
    'iphonesimulator': 'iossim',
    'watchsimulator': 'watchossim',
    'appletvsimulator': 'tvossim',
    'macosx': 'osx'
}.get(config.target_sdk_name, run_cpu)

def source_compiler_rt_libs(path):
    if os.path.exists(path):
        config.compiler_rt_libs.extend([lib for lib in
                                        os.listdir(path)
                                        if lib.startswith('libclang_rt.')
                                        and config.compiler_rt_platform in lib])

compiler_rt_dir = make_path(test_resource_dir, 'clang', 'lib',
                            platform.system().lower() if not kIsAndroid else 'android')
source_compiler_rt_libs(compiler_rt_dir)

def check_runtime_libs(features_to_check):
    for lib in config.compiler_rt_libs:
        for (libname, feature) in features_to_check.items():
            if lib.startswith("libclang_rt." + libname + "_"):
                config.available_features.add(feature)

runtime_libs = {
    'profile': 'profile_runtime',
    'asan': 'asan_runtime',
    'ubsan': 'ubsan_runtime',
    'scudo': 'scudo_runtime',
    'safestack': 'safestack_runtime',
    'fuzzer': 'fuzzer_runtime'
}

if run_ptrsize == '64' and 'libdispatch' in config.available_features:
    runtime_libs['tsan'] = 'tsan_runtime'

check_runtime_libs(runtime_libs)

# From https://stackoverflow.com/a/2393022
def strip_right(text, suffix):
    if not text.endswith(suffix):
        return text
    return text[:len(text)-len(suffix)]

base_runtime_lib_name = (
    'libclang_rt.' + strip_right(config.compiler_rt_platform, 'sim') + '.a')
if os.path.exists(make_path(compiler_rt_dir, base_runtime_lib_name)):
    config.available_features.add('c_runtime')

# For testing the remote-run utility itself, see if we can find an sftp-server
# binary.
def find_sftp_server():
    paths_to_try = ['/usr/libexec/sftp-server', '/usr/lib/sftp-server',
                    '/usr/libexec/openssh/sftp-server',
                    '/usr/lib/openssh/sftp-server']
    return next((path for path in paths_to_try if os.path.isfile(path)), None)

sftp_server_path = find_sftp_server()
if sftp_server_path:
    config.available_features.add('sftp_server')
config.substitutions.append(('%sftp-server',
                             sftp_server_path or 'no-sftp-server'))

subst_target_jit_run = ""
if 'swift_interpreter' in config.available_features:
    subst_target_jit_run = (
        "%s -interpret %s" %
        (config.target_swift_frontend, sdk_overlay_link_path))

subst_target_repl_run_simple_swift = ""
if 'swift_repl' in config.available_features:
    subst_target_repl_run_simple_swift = (
        "%s -repl %s < %%s 2>&1" %
        (config.target_swift_frontend, sdk_overlay_link_path))

config.target_parse_verify_swift = (
    '%s -typecheck -verify -disable-objc-attr-requires-foundation-module %%s'
    % (config.target_swift_frontend, ))

config.target_sil_func_extractor = (
    '%s -target %s %s'
    % (config.sil_func_extractor, config.variant_triple, mcp_opt))

config.target_sil_llvm_gen = (
    '%s -target %s %s'
    % (config.sil_llvm_gen, config.variant_triple, mcp_opt))

config.target_sil_nm = (
    '%s -target %s %s'
    % (config.sil_nm, config.variant_triple, mcp_opt))

rth_flags = ''
if swift_execution_tests_extra_flags:
    rth_flags = swift_execution_tests_extra_flags + ' -wmo'

platform_module_dir = make_path(test_resource_dir, config.target_sdk_name)
if run_vendor != 'apple':
    platform_module_dir = make_path(platform_module_dir, target_arch)

platform_dylib_dir = platform_module_dir
if run_os == 'maccatalyst' and config.darwin_maccatalyst_build_flavor == "ios-like":
    # When using the ios-macabi triple, look for module files
    # in the 'maccatalyst' compiler resource directory.
    platform_module_dir = make_path(test_resource_dir, 'maccatalyst')

lit_config.note('Using platform module dir: ' + platform_module_dir)
if test_sdk_overlay_dir:
    platform_sdk_overlay_dir = test_sdk_overlay_dir
else:
    platform_sdk_overlay_dir = platform_module_dir

# If static stdlib is present, enable static stdlib tests
static_stdlib_path = make_path(config.swift_lib_dir, "swift_static", config.target_sdk_name)
static_libswiftCore_path = make_path(static_stdlib_path, "libswiftCore.a")
if os.path.exists(static_libswiftCore_path):
    config.available_features.add("static_stdlib")
    config.substitutions.append(('%target-static-stdlib-path', static_stdlib_path))
    lit_config.note('using static stdlib path: %s' % static_stdlib_path)

# Set up testing with the standard libraries coming from the OS / just-built libraries
# default Swift tests to use the just-built libraries
target_stdlib_path = platform_dylib_dir
if not kIsWindows:
	libdispatch_path = getattr(config, 'libdispatch_artifact_dir', '')
	if 'use_os_stdlib' not in lit_config.params:
		if run_os == 'maccatalyst':
		    # Under macCatalyst we need to have the unzippered twin dylib dir come before
		    # the zippered/macosx dylib dir so that unzippered twins are picked upload_dylibs
		    # before the macOS variant.
		    target_stdlib_path = "{0}:{1}".format(platform_module_dir, target_stdlib_path)
		lit_config.note('Testing with the just-built libraries at ' + target_stdlib_path)
		config.target_run = (
			"/usr/bin/env "
			"DYLD_LIBRARY_PATH='{0}' " # Apple option
			"LD_LIBRARY_PATH='{0}:{1}' " # Linux option
			"SIMCTL_CHILD_DYLD_LIBRARY_PATH='{0}' " # Simulator option
			.format(target_stdlib_path, libdispatch_path)) + config.target_run
	else:
		config.available_features.add('use_os_stdlib')
		os_stdlib_path = ''
		if run_vendor == 'apple':
			#If we get swift-in-the-OS for non-Apple platforms, add a condition here
			os_stdlib_path = "/usr/lib/swift"
			if run_os == 'maccatalyst':
			    os_stdlib_path = "/System/iOSSupport/usr/lib/swift:/usr/lib/swift"
		all_stdlib_path = os.path.pathsep.join((os_stdlib_path, target_stdlib_path))
		lit_config.note('Testing with the standard libraries coming from the OS ' + all_stdlib_path)
		config.target_run = (
			"/usr/bin/env "
			"DYLD_LIBRARY_PATH='{0}' " # Apple option
			"LD_LIBRARY_PATH='{0}:{1}' " # Linux option
			"SIMCTL_CHILD_DYLD_LIBRARY_PATH='{0}' " # Simulator option
			.format(all_stdlib_path, libdispatch_path)) + config.target_run

if not getattr(config, 'target_run_simple_swift', None):
    config.target_run_simple_swift_parameterized = SubstituteCaptures(
        "%%empty-directory(%%t) && "
        "%s %s %%s \\1 -o %%t/a.out -module-name main  && "
        "%s %%t/a.out && "
        "%s %%t/a.out"
        % (config.target_build_swift, mcp_opt, config.target_codesign, config.target_run)
    )
    config.target_run_simple_swiftgyb_parameterized = SubstituteCaptures(
        "%%empty-directory(%%t) && "
        "%%gyb %%s -o %%t/main.swift && "
        "%%line-directive %%t/main.swift -- "
        "%s %s %%t/main.swift \\1 -o %%t/a.out -module-name main  && "
        "%s %%t/a.out && "
        "%%line-directive %%t/main.swift -- "
        "%s %%t/a.out"
        % (config.target_build_swift, mcp_opt, config.target_codesign, config.target_run)
    )

    config.target_run_simple_swift = (
        '%%empty-directory(%%t) && '
        '%s %s %%s -o %%t/a.out -module-name main  && '
        '%s %%t/a.out && '
        '%s %%t/a.out'
        % (config.target_build_swift, mcp_opt, config.target_codesign, config.target_run))
    config.target_run_stdlib_swift = (
        '%%empty-directory(%%t) && '
        '%s %s %%s -o %%t/a.out -module-name main '
        '-Xfrontend -disable-access-control  && '
        '%s %%t/a.out && '
        '%s %%t/a.out'
        % (config.target_build_swift, mcp_opt, config.target_codesign, config.target_run))
    config.target_run_simple_swiftgyb = (
        '%%empty-directory(%%t) && '
        '%%gyb %%s -o %%t/main.swift && '
        '%%line-directive %%t/main.swift -- '
        '%s %s %%t/main.swift -o %%t/a.out -module-name main  && '
        '%s %%t/a.out && '
        '%%line-directive %%t/main.swift -- '
        '%s %%t/a.out'
        % (config.target_build_swift, mcp_opt, config.target_codesign, config.target_run))
    config.target_run_stdlib_swiftgyb = (
        '%%empty-directory(%%t) && '
        '%%gyb %%s -o %%t/main.swift && '
        '%%line-directive %%t/main.swift -- '
        '%s %s %%t/main.swift -o %%t/a.out -module-name main '
        '-Xfrontend -disable-access-control  && '
        '%s %%t/a.out && '
        '%%line-directive %%t/main.swift -- '
        '%s %%t/a.out'
        % (config.target_build_swift, mcp_opt, config.target_codesign, config.target_run))

# FIXME: why can we not use %rth and have that be expanded out?
config.target_resilience_test = (
     '%s %s --target-build-swift "%s" --target-run "%s" --t %%t --S %%S '
     '--s %%s --lib-prefix "%s" --lib-suffix "%s" --target-codesign "%s" '
     '--additional-compile-flags "%s" --triple "%s"'
     % (pipes.quote(sys.executable), config.rth, config.target_build_swift,
        config.target_run, config.target_shared_library_prefix,
        config.target_shared_library_suffix, config.target_codesign,
        rth_flags, config.variant_triple))

# FIXME: Get symbol diffing working with binutils nm as well. The flags are slightly
# different.
if platform.system() != 'Darwin' or swift_test_mode == 'optimize_none_with_implicit_dynamic':
    config.target_resilience_test = ('%s --no-symbol-diff' %
                                     config.target_resilience_test)

#
# When changing substitutions, update docs/Testing.md.
#

config.substitutions.append(('%target-runtime', config.target_runtime))

config.substitutions.append(('%target-typecheck-verify-swift', config.target_parse_verify_swift))

config.substitutions.append(('%target-swift-emit-silgen\(mock-sdk:([^)]+)\)',
                             SubstituteCaptures(r'%target-swift-frontend(mock-sdk:\1) -emit-silgen -verify-syntax-tree')))
config.substitutions.append(('%target-swift-emit-silgen', '%target-swift-frontend -emit-silgen -verify-syntax-tree'))
config.substitutions.append(('%target-swift-emit-sil\(mock-sdk:([^)]+)\)',
                             SubstituteCaptures(r'%target-swift-frontend(mock-sdk:\1) -emit-sil -verify-syntax-tree')))
config.substitutions.append(('%target-swift-emit-sil', '%target-swift-frontend -emit-sil -verify-syntax-tree'))
config.substitutions.append(('%target-swift-emit-ir\(mock-sdk:([^)]+)\)',
                             SubstituteCaptures(r'%target-swift-frontend(mock-sdk:\1) -emit-ir -verify-syntax-tree')))
config.substitutions.append(('%target-swift-emit-ir', '%target-swift-frontend -emit-ir -verify-syntax-tree'))
config.substitutions.append(('%target-swift-frontend\(mock-sdk:([^)]+)\)',
                             SubstituteCaptures(r'%s \1 %s' % (subst_target_swift_frontend_mock_sdk,
                                                               subst_target_swift_frontend_mock_sdk_after))))
config.substitutions.append(('%target-swift-frontend', config.target_swift_frontend))


config.substitutions.append(('%target-run-simple-swiftgyb\(([^)]+)\)',
                            config.target_run_simple_swiftgyb_parameterized))
config.substitutions.append(('%target-run-simple-swiftgyb', config.target_run_simple_swiftgyb))
config.substitutions.append(('%target-run-simple-swift\(([^)]+)\)',
                            config.target_run_simple_swift_parameterized))
config.substitutions.append(('%target-run-simple-swift', config.target_run_simple_swift))
config.substitutions.append(('%target-run-stdlib-swiftgyb', config.target_run_stdlib_swiftgyb))
config.substitutions.append(('%target-run-stdlib-swift', config.target_run_stdlib_swift))
config.substitutions.append(('%target-repl-run-simple-swift', subst_target_repl_run_simple_swift))
config.substitutions.append(('%target-run', config.target_run))
config.substitutions.append(('%target-jit-run', subst_target_jit_run))
config.substitutions.append(('%target-build-swift-dylib\(([^)]+)\)', config.target_build_swift_dylib))
config.substitutions.append(('%target-codesign', config.target_codesign))
config.substitutions.append(('%target-build-swift', config.target_build_swift))
config.substitutions.append(('%target-clang', config.target_clang))
config.substitutions.append(('%target-ld', config.target_ld))
if hasattr(config, 'target_cc_options'):
    config.substitutions.append(('%target-cc-options', config.target_cc_options))
else:
    config.substitutions.append(('%target-cc-options', ''))

# WORKAROUND(rdar://53507844): On some macOS versions, we see flaky failures in
# tests which create a hard link to an executable and immediately invoke it.
# Work around this by always copying on Darwin.
if platform.system() == 'Darwin':
  config.substitutions.append(
      (r'%hardlink-or-copy\(from: *(.*), *to: *(.*)\)',
       SubstituteCaptures(r'cp \1 \2')))
else:
  config.substitutions.append(
      (r'%hardlink-or-copy\(from: *(.*), *to: *(.*)\)',
       SubstituteCaptures(r'ln \1 \2 || cp \1 \2')))

config.substitutions.append(('%utils', config.swift_utils))
config.substitutions.append(('%line-directive', '%s %s' % (pipes.quote(sys.executable), config.line_directive)))
config.substitutions.append(('%gyb', '%s %s' % (pipes.quote(sys.executable), config.gyb)))
config.substitutions.append(('%round-trip-syntax-test',
                             '%s %s' % (pipes.quote(sys.executable),
                                        config.round_trip_syntax_test)))
config.substitutions.append(('%rth', '%s %s' % (pipes.quote(sys.executable), config.rth)))
config.substitutions.append(('%scale-test',
                             '{} {} --swiftc-binary={} --tmpdir=%t'.format(
                                 pipes.quote(sys.executable), config.scale_test,
                                 config.swiftc)))
config.substitutions.append(('%empty-directory\(([^)]+)\)',
                             SubstituteCaptures(r'rm -rf "\1" && mkdir -p "\1"')))

config.substitutions.append(('%target-sil-opt\(mock-sdk:([^)]+)\)',
                             SubstituteCaptures(r'%s \1 %s' % (subst_target_sil_opt_mock_sdk,
                                                               subst_target_sil_opt_mock_sdk_after))))
# NOTE: This needs to be appended after the mock-sdk expansion to ensure that we
# first expand the mock-sdk when lit is processing.
config.substitutions.append(('%target-sil-opt', config.target_sil_opt))

config.substitutions.append(('%target-sil-func-extractor', config.target_sil_func_extractor))
config.substitutions.append(('%target-sil-llvm-gen', config.target_sil_llvm_gen))
config.substitutions.append(('%target-sil-nm', config.target_sil_nm))

config.substitutions.append(('%target-swift-ide-test\(mock-sdk:([^)]+)\)',
                             SubstituteCaptures(r'%s \1 %s -swift-version %s' % (subst_target_swift_ide_test_mock_sdk,
                                                                                 subst_target_swift_ide_test_mock_sdk_after,
                                                                                 swift_version))))
config.substitutions.append(('%target-swift-ide-test', "%s -swift-version %s" % (config.target_swift_ide_test, swift_version)))

config.substitutions.append(('%target-swift-symbolgraph-extract', config.target_swift_symbolgraph_extract))

if not hasattr(config, 'target_swift_reflection_test'):
    config.target_swift_reflection_test = inferSwiftBinary(swift_reflection_test_name)

config.substitutions.append(('%target-swift-reflection-test', config.target_swift_reflection_test))

config.substitutions.append(('%target-swift-reflection-dump', '{} {} {}'.format(config.swift_reflection_dump, '-arch', run_cpu)))
config.substitutions.append(('%target-swiftc_driver', config.target_swiftc_driver))
config.substitutions.append(('%target-swift-remoteast-test-with-sdk',
                             '%s -sdk %r' %
                               (config.swift_remoteast_test, config.variant_sdk)))
config.substitutions.append(('%target-swift-remoteast-test', config.swift_remoteast_test))

if hasattr(config, 'target_swift_autolink_extract'):
    config.available_features.add('autolink-extract')
    config.substitutions.append(('%target-swift-autolink-extract',
                                 config.target_swift_autolink_extract))

config.substitutions.append(('%target-swift-modulewrap',
                             config.target_swift_modulewrap))
config.substitutions.append(('%target-swift-emit-pcm',
                             config.target_swift_emit_pcm))

config.substitutions.insert(0, ('%platform-module-dir', platform_module_dir))
config.substitutions.insert(0, ('%platform-sdk-overlay-dir', platform_sdk_overlay_dir))
config.substitutions.insert(0, ('%platform-dylib-dir', platform_dylib_dir))
config.substitutions.insert(0, ('%test-resource-dir', test_resource_dir))

if run_vendor != 'apple':
    extra_frameworks_dir = ''
config.substitutions.append(('%xcode-extra-frameworks-dir', extra_frameworks_dir))

config.substitutions.append(('%target-swiftmodule-name', target_specific_module_triple + '.swiftmodule'))
config.substitutions.append(('%target-swiftdoc-name', target_specific_module_triple + '.swiftdoc'))
config.substitutions.append(('%target-swiftsourceinfo-name', target_specific_module_triple + '.swiftsourceinfo'))
config.substitutions.append(('%target-swiftinterface-name', target_specific_module_triple + '.swiftinterface'))

config.substitutions.append(('%target-object-format', config.target_object_format))
config.substitutions.append(('%{target-shared-library-prefix}', config.target_shared_library_prefix))
config.substitutions.append(('%{target-shared-library-suffix}', config.target_shared_library_suffix))
config.substitutions.insert(0, ('%target-library-name\(([^)]+)\)',
                                SubstituteCaptures(r'%s\1%s' % (config.target_shared_library_prefix,
                                                                config.target_shared_library_suffix))))
config.substitutions.append(('%target-rpath\(([^)]+)\)',
                             SubstituteCaptures(config.target_add_rpath)))

config.substitutions.append(('%target-resilience-test', config.target_resilience_test))

config.substitutions.append(('%llvm-profdata', config.llvm_profdata))
config.substitutions.append(('%llvm-cov', config.llvm_cov))

if hasattr(config, 'otool_classic'):
    config.substitutions.append(('%otool-classic', config.otool_classic))

config.substitutions.append(('%FileCheck',
                             '%s %r --sanitize BUILD_DIR=%r --sanitize SOURCE_DIR=%r --use-filecheck %r %s' % (
        pipes.quote(sys.executable),
        config.PathSanitizingFileCheck,
        swift_obj_root,
        config.swift_src_root,
        config.filecheck,
        '--enable-windows-compatibility' if kIsWindows else '')))
config.substitutions.append(('%raw-FileCheck', pipes.quote(config.filecheck)))
config.substitutions.append(('%import-libdispatch', getattr(config, 'import_libdispatch', '')))

if config.lldb_build_root != "":
    lldb_python_path = get_lldb_python_path(config.lldb_build_root)
    lldb_python_interpreter = get_lldb_python_interpreter(config.lldb_build_root)
    if lldb_python_path == None:
        lit_config.warning("""
        Specified lldb_build_root, but could not find lldb in that build root
        """)
    elif lldb_python_interpreter == None:
        lit_config.warning("""
        Specified lldb_build_root, but could not find lldb-python in that build root
        """)
    else:
        config.available_features.add('lldb')
        config.substitutions.append(('%lldb-python-path', lldb_python_path))
        config.substitutions.append(('%{lldb-python}', 'PYTHONPATH=%s %s' % (lldb_python_path, lldb_python_interpreter)))

# Disable randomized hash seeding by default. Tests need to manually opt in to
# random seeds by unsetting the SWIFT_DETERMINISTIC_HASHING environment
# variable.
config.environment[TARGET_ENV_PREFIX + 'SWIFT_DETERMINISTIC_HASHING'] = '1'

# Enable malloc scribble during tests by default.
config.environment[TARGET_ENV_PREFIX + 'SWIFT_DEBUG_ENABLE_MALLOC_SCRIBBLE'] = 'YES'

# Enable COW sanity checks in the swift runtime by default.
config.environment['SWIFT_DEBUG_ENABLE_COW_SANITY_CHECKS'] = 'true'

# Run lsb_release on the target to be tested and return the results.
def linux_get_lsb_release():
    lsb_release_path = '/usr/bin/lsb_release'
    if os.path.isfile(lsb_release_path) and os.access(lsb_release_path, os.X_OK):
        distributor = lit.util.executeCommand([lsb_release_path, '-is'])[0].rstrip()
        release = lit.util.executeCommand([lsb_release_path, '-rs'])[0].rstrip()
        return (distributor, release)
    return ('', '')

if platform.system() == 'Linux':
    (distributor, release) = linux_get_lsb_release()
    if distributor != '' and release != '':
        config.available_features.add("LinuxDistribution=" + distributor + '-' + release)
        lit_config.note('Running tests on %s-%s' % (distributor, release))

# Copy environment variables specified in --param copy_env=..., overriding
# anything computed here. It's assumed that the person setting this knows what
# they're doing.
copy_env = lit_config.params.get('copy_env', None)
if copy_env is not None:
  for key in copy_env.split(':'):
    config.environment[key] = os.environ[key]

lit_config.note("Available features: " + ", ".join(sorted(config.available_features)))

# On macOS reflection information is read through the dyld APIs
# On other platorms, this information is exported through extra
# entry points in the Swift runtime that are only available in debug builds.
# Windows currently does not support basic reflection support.
if 'objc_interop' in config.available_features or ('swift_stdlib_asserts' in config.available_features and not kIsWindows):
    config.available_features.add('reflection_test_support')

# num_extra_inhabitants on 64 bits differs between Mac and everywhere else.
# Add it, as a variable in order to substitute it in the tests
if platform.system() == 'Darwin':
    num_extra_inhabitants_64bit = 2147483647
else:
    num_extra_inhabitants_64bit = 4096
add_num_extra_inhabitants = "-D#num_extra_inhabitants_64bit={} ".format(num_extra_inhabitants_64bit)
config.substitutions.append(('%add_num_extra_inhabitants', add_num_extra_inhabitants))

